home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / program / cgazv4n2.zip / EXPANDWI.C < prev    next >
Text File  |  1989-11-03  |  25KB  |  567 lines

  1. /********************************** EXPANDWI.C ********************************
  2. *    Expand wildcard file names in a "ragged" string array into a new array.
  3. *
  4. *    SYNOPSIS:   int expandwild(pnOut, pvOut, nIn, vIn, attrib) 
  5. *
  6. *    nIn: no. of strings in vIn; if < 0, stop when vIn[i] == NULL.
  7. *
  8. *    vIn: array of pointers to strings, e.g., argv. Wildcard strings
  9. *         expanded to full file name and path in *pvOut, all strings which
  10. *         don't expand are copied unchanged.
  11. *
  12. *   attrib: attribute byte of files to be returned, see FA_xxxxxx constants.
  13. *
  14. *   pnOut: points to int to return no. of strings in pvOut.
  15. *   pvOut: points to pointer to output array, *pvOut[*pnOut] == NULL.
  16. *
  17. *   Return value: 0 if successful, non-0 (see codes below) if errors.
  18. *
  19. *   AUTHOR: Bill Lee, 5132 106A St., Edmonton, Alberta, Canada T6H 2W7
  20. *       CompuServe 70441,2372.
  21. *
  22. *   Copyright (C) by Bill Lee, 1989. All rights reserved.
  23. *   Use freely for any non-military purpose but retain copyright notice.
  24. *
  25. *   COMPILATION OPTIONS:    All memory models of two compilers are supported;
  26. *   for your compiler, define the appropriate constant if needed:
  27. *   +   (none, the assumed default): Microsoft C 5.1 for DOS only.
  28. *   +   OS2:  With Microsoft C 5.1, use OS/2 v1.1 family API (FAPI) for the
  29. *       find-file functions; can then be "bound" to run under DOS or under
  30. *       protected mode. Header files from Microsoft OS/2 Presentation Manager
  31. *       Toolkit v1.1 needed. expandwi.c is probably re-entrant for
  32. *       multithreading but not tested.
  33. *   +   (none, detects __TURBOC__):  Turbo C 2.0 under DOS.
  34. *   +   Define MAIN to generate a main() test driver.
  35. *
  36. *   VERSION:  1.1, 89aug26.
  37. ***************************************************************************/
  38.  
  39. #if defined(__TURBOC__)
  40. #include <string.h>
  41. #include <stdio.h>
  42. #include <dos.h>
  43. #include <alloc.h>
  44.  
  45. /*  Normally, dir.h is included for the prototypes of findfirst()
  46.     and findnext(), but it was necessary to code them below with a
  47.     modification for the MSC structure name which is used here. */
  48.  
  49. int _Cdecl findfirst(char *, struct find_t *, int);
  50. int _Cdecl findnext(struct find_t *);
  51.  
  52. /*  MSC 5.1 and TurboC 2.0 provide the directory find-first and find-next
  53.     file functions in slightly different flavours; the following macros
  54.     adapt the MSC DOS functions calls for use with the TurboC RTL.        */
  55.  
  56. #define _dos_findfirst(path, attr, buff)    findfirst((path), (buff), (attr))
  57. #define _dos_findnext(buff)                 findnext((buff))
  58.  
  59. /*  Structure used by _dos_findfirst() and _dos_findnext(), a-la MSC  */
  60. struct find_t {
  61.     char reserved[21];                  /* workarea */
  62.     char attrib;                        /* file attribute bit flags */
  63.     unsigned int wr_time;               /* packed time of last file write */
  64.     unsigned int wr_date;               /* packed date of last file write */
  65.     long size;                          /* file size */
  66.     char name[13];                      /* file name.ext, no blanks */
  67. };
  68.  
  69. #else                                   /* MSC */
  70.  
  71. #include <stdio.h>
  72. #include <stddef.h>
  73. #include <string.h>
  74. #include <malloc.h>
  75. #if !defined(OS2)
  76. #include <dos.h>                        /* _dos_findfirst/_dos_findnext */
  77. #else
  78. #define INCL_DOSFILEMGR                 /* OS/2 file mgmt */
  79. #define INCL_DOSMISC                    /* for DosGetMachineMode() */
  80. #define INCL_NOPM                       /* save compile time, exclude PM */
  81. #include <os2.h>                        /* MS Pres Mgr Toolkit */
  82. #endif  /* #if !defined(OS2) */
  83.  
  84. /*  MSC lacks Turbo C's stpcpy(); this macro is an adequate
  85.     replacement for non-overlapping src and dest.  */
  86.  
  87. #define stpcpy(dest, src)   (strcpy((dest), (src)) + strlen(src))
  88.  
  89. #endif  /* #if defined(__TURBOC__) */
  90.  
  91. /*  Maximum lengths of fnsplitE() input and output strings including \0.  */
  92. #define MAXPATH     80                  /* input maximum */
  93. #define MAXDRIVE    3
  94. #define MAXDIR      66
  95. #define MAXFILE     9
  96. #define MAXEXT      5
  97.  
  98. /*  Bit masks for fnsplitE() return value  */
  99. #define WILDCARDS   0x01                /* '*' and/or '?' in filename or ext */
  100. #define EXTENSION   0x02                /* extension present */
  101. #define FILENAME    0x04                /* filename present */
  102. #define DIRECTORY   0x08                /* directory present */
  103. #define DRIVE       0x10                /* drive: present */
  104. /*  Bit masks for returning truncation errors in fnsplitE()  */
  105. #define PATHt       0x0100              /* input path truncated */
  106. #define EXTENSIONt  (EXTENSION << 8)    /* extension truncated */
  107. #define FILENAMEt   (FILENAME << 8)     /* filename truncated */
  108. #define DIRECTORYt  (DIRECTORY << 8)    /* directory truncated */
  109. #define DRIVEt      (DRIVE << 8)        /* drive truncated (can't happen) */
  110. #define FNSPLITEt   (PATHt | EXTENSIONt | FILENAMEt | DIRECTORYt | DRIVEt)
  111.                                         /* all of the above */
  112.  
  113. /*  Function prototypes  */
  114. int expandwild (int *, char **[], int, char *[], int);
  115. int fnsplitE (char *, char *, char *, char *, char *);
  116. int fnsplitEa (char *, char *, char *, unsigned int, int);
  117.  
  118. /*  Codes returned for errors detected by expandwild().
  119.     (Remember to update rmsg[] in main() if these codes are changed.)  */
  120.  
  121. #define EXWINOMEM   1               /* not enough memory */
  122. #define EXWICNTCHG  2               /* count changed between passes */
  123. #define EXWISIZCHG  3               /* array size changed between passes */
  124.  
  125. /*---------------------------------------------------------------------------*/
  126.  
  127. int expandwild(int *pnOut,          /* ptr to no. of strings in output array */
  128. char **pvOut[],                     /* ptr to output array */
  129. int nIn,                            /* no. of strings in vIn */
  130. char *vIn[],                        /* input string array */
  131. int attrib)                         /* file attribute byte */
  132. {
  133.     char drive[MAXDRIVE];           /* fnsplitE() workarea */
  134.     char dir[MAXDIR];               /* fnsplitE() workarea */
  135.     #if !defined(OS2)               /* use DOS directory search */
  136.     struct find_t fblk;             /* for _dos_findfirst()/_dos_findnext() */
  137.     #else                           /* use OS/2 directory search */
  138.     BYTE bMachineMode;              /* for DosGetMachineMode() */
  139.     FILEFINDBUF fblk;               /* for DosFindFirst()/DosFindNext() */
  140.     HDIR hDir;                      /* handle for directory search */
  141.     USHORT usSrchCnt;               /* count: elements in fblk */
  142.     #endif
  143.     char *pvIn;                     /* work ptr into vIn[] */
  144.     char **vOut = NULL;             /* anchor for new output array */
  145.     char *vOutEnd;                  /* last byte of new array */
  146.     char *pvTmp;                    /* temp ptr to vOut[] */
  147.     unsigned int iIn;               /* index into vIn[] */
  148.     unsigned int vOutSize;          /* accumulate memory size of new array */
  149.     unsigned int nOut;              /* count strings in new array */
  150.     unsigned int iOut;              /* string index in new array */
  151.     unsigned int fixSize;           /* size of fixed part of a new string */
  152.     int fnsFlg;                     /* flags returned by fnsplitE() */
  153.     int err = 0;                    /* error code returned by expandwild() */
  154.  
  155.     vOutSize = sizeof(pvOut[0]);    /* space for NULL ptr in new array */
  156.  
  157.     #if defined(OS2)
  158.     DosGetMachineMode(&bMachineMode); /* returns MODE_PROTECTED or MODE_REAL */
  159.     #endif  /* #if defined(OS2) */
  160.  
  161.     /*  Determine no. and total size of strings required for new array.  */
  162.     for (nOut = 0, iIn = 0;
  163.       (pvIn = vIn[iIn]) != NULL && (nIn < 0 || (nIn >= 0 && iIn < nIn));
  164.       iIn++) {
  165.         /*  If no truncation and if a wildcard and if a file name is found,
  166.             save space for expanded filename string.  */
  167.         #if !defined(OS2)           /* DOS-only functions for finding files */
  168.         if (!((fnsFlg = fnsplitE(pvIn, drive, dir, NULL, NULL)) & FNSPLITEt)
  169.           && fnsFlg & WILDCARDS && !_dos_findfirst(pvIn, attrib, &fblk)) {
  170.             fixSize = sizeof(pvOut[0]) + strlen(drive) + strlen(dir) + 1;
  171.             do {
  172.                 nOut++;
  173.                 vOutSize += fixSize + strlen(fblk.name);
  174.             } while (!_dos_findnext(&fblk));
  175.         }
  176.         #else                       /* OS/2 functions for finding files */
  177.         /*  Set hDir based on mode, so protected mode can multithread. */
  178.         if (bMachineMode == MODE_PROTECTED)
  179.             hDir = HDIR_CREATE;     /* so protected mode can multithread */
  180.         else                        /* bMachineMode == MODE_REAL */
  181.             hDir = HDIR_SYSTEM;     /* required for DOS directory search */
  182.         usSrchCnt = 1;              /* initialize count */
  183.         if (!((fnsFlg = fnsplitE(pvIn, drive, dir, NULL, NULL)) & FNSPLITEt)
  184.           && fnsFlg & WILDCARDS
  185.           && !DosFindFirst(pvIn, &hDir, attrib, &fblk, sizeof(fblk),
  186.                 &usSrchCnt, 0L)) /* open handle, find 1st file */ {
  187.             fixSize = sizeof(pvOut[0]) + strlen(drive) + strlen(dir) + 1;
  188.             do {
  189.                 nOut++;
  190.                 vOutSize += fixSize + strlen(fblk.achName);
  191.             } while (!DosFindNext(hDir, &fblk, sizeof(fblk), &usSrchCnt));
  192.             DosFindClose(hDir);     /* close directory search handle */
  193.         }
  194.         #endif  /* #if !defined(OS2) */
  195.         else {                      /* save space for non-expanded string */
  196.             nOut++;
  197.             vOutSize += sizeof(pvOut[0]) + strlen(pvIn) + 1;
  198.         }
  199.     }   /* for (iIn = 0; nOut = 0; ... ) */
  200.  
  201.     /*  Note that the logic above and below does not call DosFindClose() when
  202.         DosFindFirst() returns an error code.  This appears to be ok in v1.1
  203.         of OS/2 as DosFindFirst() returns an invalid handle which cannot be
  204.         closed anyway.  But you might watch it in future releases.  */
  205.  
  206.     /*  Allocate memory for new array.  */
  207.     if ((vOut = (char **) malloc(vOutSize)) == NULL)
  208.         err = EXWINOMEM;                            /* not enough memory */
  209.     else {
  210.         vOut[0] = (char *) (vOut + nOut + 1);       /* ptr to 1st string */
  211.         vOutEnd = (char *) vOut + vOutSize;         /* 1st byte after last */
  212.     }
  213.  
  214.     /*  Go through again and copy strings to new array.  */
  215.     for (iOut = 0, iIn = 0; err == 0
  216.       && (pvIn = vIn[iIn]) != NULL && (nIn < 0 || (nIn >= 0 && iIn < nIn));
  217.       iIn++) {
  218.         /*  If no truncation and if wildcard and if file name is found,
  219.             save expanded string.  */
  220.         #if !defined(OS2)           /* DOS-only functions for finding files */
  221.         if (!((fnsFlg = fnsplitE(pvIn, drive, dir, NULL, NULL)) & FNSPLITEt)
  222.           && fnsFlg & WILDCARDS && !_dos_findfirst(pvIn, attrib, &fblk)) {
  223.             fixSize = strlen(drive) + strlen(dir) + 1;
  224.             do {
  225.                 if (iOut >= nOut)               /* count changed? */
  226.                     err = EXWICNTCHG;           /* 2nd pass count too big */
  227.                 else {
  228.                     pvTmp = vOut[iOut];
  229.                     if (pvTmp + fixSize + strlen(fblk.name) > vOutEnd)
  230.                         err = EXWISIZCHG;       /* overflow */
  231.                     else    /* copy full name, save ptr to next new string */
  232.                         vOut[++iOut] = 1 +      /* whew! */
  233.                           stpcpy(stpcpy(stpcpy(pvTmp,drive),dir),fblk.name);
  234.                 }
  235.             } while (err == 0 && !_dos_findnext(&fblk));
  236.         }
  237.         #else                           /* OS/2 functions for finding files */
  238.         /*  Set hDir based on mode, so protected mode can multithread. */
  239.         if (bMachineMode == MODE_PROTECTED)
  240.             hDir = HDIR_CREATE;         /* so protected mode can multithread */
  241.         else                            /* bMachineMode == MODE_REAL */
  242.             hDir = HDIR_SYSTEM;         /* required for DOS directory search */
  243.         usSrchCnt = 1;                  /* initialize count */
  244.         if (!((fnsFlg = fnsplitE(pvIn, drive, dir, NULL, NULL)) & FNSPLITEt)
  245.           && fnsFlg & WILDCARDS
  246.           && !DosFindFirst(pvIn, &hDir, attrib, &fblk, sizeof(fblk),
  247.                 &usSrchCnt, 0L)) /* re-open handle, find 1st file */ {
  248.             fixSize = strlen(drive) + strlen(dir) + 1;
  249.             do {
  250.                 if (iOut >= nOut)               /* count changed? */
  251.                     err = EXWICNTCHG;           /* 2nd pass count too big */
  252.                 else {
  253.                     pvTmp = vOut[iOut];
  254.                     if (pvTmp + fixSize + strlen(fblk.achName) > vOutEnd)
  255.                         err = EXWISIZCHG;       /* overflow */
  256.                     else    /* copy full name, save ptr to next new string */
  257.                         vOut[++iOut] = 1 +      /* whew! */
  258.                           stpcpy(stpcpy(stpcpy(pvTmp,drive),dir),fblk.achName);
  259.                 }
  260.             } while (err == 0
  261.                 && !DosFindNext(hDir, &fblk, sizeof(fblk), &usSrchCnt));
  262.             DosFindClose(hDir);         /* close directory search handle */
  263.         }
  264.         #endif  /* #if !defined(OS2) */
  265.         else {                          /* copy non-wildcard to new array */
  266.             if (iOut >= nOut)           /* count changed? */
  267.                 err = EXWICNTCHG;       /* 2nd pass count too big */
  268.             else {
  269.                 pvTmp = vOut[iOut];
  270.                 if (pvTmp + strlen(pvIn) + 1 > vOutEnd)
  271.                     err = EXWISIZCHG;   /* overflow */
  272.                 else        /* copy non-wildcard, save ptr to next new string*/
  273.                     vOut[++iOut] = 1 + stpcpy(pvTmp, pvIn);
  274.             }
  275.         }
  276.     }   /* for (iIn = 0; iOut = 0; ... ) */
  277.  
  278.     if (err == 0)
  279.         /*  Check for changes in count or size between 2 passes thru names.  */
  280.         if (iOut != nOut)               /* count changed? */
  281.             err = EXWICNTCHG;           /* 2nd pass count smaller */
  282.         else if (vOut[nOut] != vOutEnd) /* size changed? */
  283.             err = EXWISIZCHG;           /* 2nd pass size smaller */
  284.  
  285.     if (err == 0) {                 /* if no error, return results to caller */
  286.         vOut[nOut] = NULL;          /* terminate array as per ANSI standard  */
  287.         *pnOut = nOut;
  288.         *pvOut = vOut;
  289.     }
  290.     else if (vOut != NULL)
  291.         free((char *) vOut);
  292.  
  293.     return (err);
  294.  
  295. }   /* expandwild() */
  296.  
  297. /*---------------------------------------------------------------------------*/
  298.  
  299. /*  fnsplitE():
  300.     Split full file name path string into component parts--drive, directory,
  301.     file name, and file name extension.  Returns bit flags indicating which
  302.     parts are in the input and whether any input was truncated because it is
  303.     too long.  This is a work-alike function of fnsplit() in Turbo C 1.0 except
  304.     the latter does not indicate truncation errors.  */
  305.  
  306. int fnsplitE(char *path,        /* input path       */
  307. char *drive,                    /* output drive     */
  308. char *dir,                      /* output directory */
  309. char *name,                     /* output file name */
  310. char *ext)                      /* output file name extension */
  311. {
  312.     int flags = 0;              /* bit flags return value */
  313.     char *pL, *pR;              /* Left & Right-hand ptrs into path */
  314.     unsigned int nchar;         /* no. of characters */
  315.  
  316.     /*  Initialize output to null strings where present in case component
  317.         absent in input.  */
  318.     if (drive != NULL)        *drive = '\0';
  319.     if (dir   != NULL)        *dir   = '\0';
  320.     if (name  != NULL)        *name  = '\0';
  321.     if (ext   != NULL)        *ext   = '\0';
  322.  
  323.     while (*path == ' ')        /* skip any leading spaces in input */
  324.         ++path;
  325.  
  326.     /*  Truncate input if too long.
  327.         (Turbo C fnsplit() uses MAXPATH, not MAXPATH - 1.)   */
  328.     if ((nchar = strlen(path)) > MAXPATH - 1) {
  329.         nchar = MAXPATH - 1;
  330.         flags |= PATHt;         /* indicate truncation error */
  331.     }
  332.     /*  Return if path null; only needed if path at segment offset 0. */
  333.     if (nchar == 0)
  334.         return(flags);
  335.  
  336.     /*  Initialize current Left and Right ends to the terminal \0.  */
  337.     pL = pR = path + nchar;
  338.  
  339.     /*  Reverse scan thru input path string.  */
  340.     while (--pL >= path) {
  341.  
  342.         /*  Check for special character in input path string.  */
  343.         switch (*pL) {
  344.             case '.':           /* possible left-most char of extension */
  345.                 /*  Extension, only if we're not already past it.  */
  346.                 if (!(flags & (DRIVE | DIRECTORY | FILENAME | EXTENSION))) {
  347.                     flags |= fnsplitEa(pL, pR, ext, MAXEXT - 1, EXTENSION);
  348.                     pR = pL;
  349.                 }
  350.                 break;
  351.             case '*':           /* wildcard if in filename or extension */
  352.             case '?':
  353.                 if (!(flags & (DRIVE | DIRECTORY)))
  354.                     flags |= WILDCARDS;
  355.                 break;
  356.             case '\\':          /* possible directory indication */
  357.             case '/':
  358.                 if (!(flags & (DRIVE | DIRECTORY | FILENAME))) {
  359.                     flags |= fnsplitEa(++pL, pR, name, MAXFILE - 1, FILENAME);
  360.                     pR = pL--;
  361.                 }
  362.                 if (!(flags & (DRIVE | DIRECTORY)))
  363.                     flags |= DIRECTORY;
  364.                 break;
  365.             case ':':           /* right-most char of 2-char drive? */
  366.                 if (pL == path + 1) {   /* colon must be here to be a drive */
  367.                     if (!(flags & (DRIVE | DIRECTORY | FILENAME))) {
  368.                         flags |= fnsplitEa(++pL, pR, name, MAXFILE - 1,
  369.                           FILENAME);
  370.                         pR = pL--;
  371.                     }
  372.                     else if (flags & DIRECTORY) {
  373.                         flags |= fnsplitEa(++pL, pR, dir, MAXDIR - 1,
  374.                           DIRECTORY);
  375.                         pR = pL--;
  376.                     }
  377.                     flags |= DRIVE;
  378.                 }
  379.         }   /* switch (*pL) */
  380.  
  381.         /*  If back to start of input string, deal with input that remains.  */
  382.         if (pL == path) {
  383.             if (!(flags & (DRIVE | DIRECTORY | FILENAME)))
  384.                 flags |= fnsplitEa(pL, pR, name, MAXFILE - 1, FILENAME);
  385.             else if (flags & DRIVE)
  386.                 flags |= fnsplitEa(pL, pR, drive, MAXDRIVE - 1, DRIVE);
  387.             else                /* only dir remains */
  388.                 flags |= fnsplitEa(pL, pR, dir, MAXDIR - 1, DIRECTORY);
  389.             break;              /* stop loop if path segment offset == 0 */
  390.         }
  391.  
  392.     }   /* while (--pL >= path) */
  393.  
  394.     return (flags);
  395.  
  396. }   /* fnsplitE() */
  397.  
  398. /*  fnsplitEa() copies string to output using left/right ptrs to input. */
  399.  
  400. int fnsplitEa(char *pL,         /* Left-hand ptr to input */
  401. char *pR,                       /* Right-hand ptr to input */
  402. char *pOut,                     /* ptr to output, can be NULL */
  403. unsigned int maxOut,            /* max non-null char to *pOut excluding \0 */
  404. int flag)                       /* fnsplitE() flag bit */
  405. {
  406.     unsigned int nchar;         /* no. of characters */
  407.  
  408.     if ((nchar = pR - pL) > maxOut) {   /* too long for output? */
  409.         nchar = maxOut;                 /* yes, truncate */
  410.         flag |= flag << 8;              /* indicate truncation to caller */
  411.     }
  412.     if (pOut != NULL) {                 /* any output area? */
  413.         strncpy(pOut, pL, nchar);       /* copy to output */
  414.         *(pOut + nchar) = '\0';         /* terminal \0 */
  415.     }
  416.  
  417.     return (nchar > 0 ? flag : 0);      /* return flag if input not empty */
  418.  
  419. }   /* fnsplitEa() */
  420.  
  421. /*---------------------------------------------------------------------------*/
  422.  
  423. #if defined(MAIN)
  424.  
  425. /*  main() test driver for expandwild().  */
  426.  
  427. /*  File attributes a-la MSC for TC or for use with OS/2  */
  428. #if defined(__TURBOC__) || defined(OS2)
  429. #define _A_NORMAL   0x00                /* Normal file--no attribute bits */
  430. #define _A_RDONLY   0x01                /* Read only attribute */
  431. #define _A_HIDDEN   0x02                /* Hidden file */
  432. #define _A_SYSTEM   0x04                /* System file */
  433. #define _A_VOLID    0x08                /* Volume label--ignored for OS/2 */
  434. #define _A_SUBDIR   0x10                /* Subdirectory */
  435. #define _A_ARCH     0x20                /* Archive */
  436. #endif  /* #if defined(__TURBOC__) */
  437.  
  438. #if defined(OS2)
  439. #define _A_ALLBITS  (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|         _A_SUBDIR|_A_ARCH)
  440. #else
  441. #define _A_ALLBITS  (_A_RDONLY|_A_HIDDEN|_A_SYSTEM|_A_VOLID|_A_SUBDIR|_A_ARCH)
  442. #endif
  443.  
  444. unsigned int xtoi(char []);
  445.  
  446. int main(int argc,
  447. char *argv[])                   /* argv[1] is attribute byte in ASCII hex */
  448. {
  449.     unsigned int attrib;        /* attribute byte from argv[1] via xtoi() */
  450.     int i;                      /* argv/newargv index */
  451.     int rc;                     /* return code from expandwild() */
  452.     int newargc;                /* count of expanded arg strings */
  453.     char **newargv;             /* ptr to new array of expanded arg strings */
  454.  
  455.     /*  Msgs for errors detected by expandwild().  */
  456.     static char *rmsg[] = {
  457.         "successful",                                   /* 0 */
  458.         "not enough memory for output",                 /* 1 EXWINOMEM */
  459.         "output count change between passes",           /* 2 EXWICNTCHG */
  460.         "output size change between passes"             /* 3 EXWISIZCHG */
  461.     };
  462.  
  463.     #if !defined(__TURBOC__)
  464.         static char compiler[] = "Microsoft C";
  465.     #if defined(M_I86SM)
  466.         static char model[] = "small model";
  467.     #elif defined(M_I86MM)
  468.         static char model[] = "medium model";
  469.     #elif defined(M_I86CM)
  470.         static char model[] = "compact model";
  471.     /*  Test M_I86HM before M_I86LM because both defined in huge model.  */
  472.     #elif defined(M_I86HM)
  473.         static char model[] = "huge model";
  474.     #elif defined(M_I86LM)
  475.         static char model[] = "large model";
  476.     #endif
  477.  
  478.     #else
  479.         static char compiler[] = "Turbo C";
  480.     #if defined(__TINY__)
  481.         static char model[] = "tiny model";
  482.     #elif defined(__SMALL__)
  483.         static char model[] = "small model";
  484.     #elif defined(__MEDIUM__)
  485.         static char model[] = "medium model";
  486.     #elif defined(__COMPACT__)
  487.         static char model[] = "compact model";
  488.     #elif defined(__LARGE__)
  489.         static char model[] = "large model";
  490.     #elif defined(__HUGE__)
  491.         static char model[] = "huge model";
  492.     #endif
  493.     #endif
  494.  
  495.     fprintf(stderr, "Test expandwild(), %s %s"
  496.         #if defined(OS2)
  497.         " (OS/2)"
  498.         #endif
  499.         "\n", compiler, model);
  500.  
  501.     /*  Check range of no. of args and value of attribute byte.  */
  502.     if (argc < 2 || (attrib = xtoi(argv[1])) == 0xffff
  503.       || attrib & (_A_ALLBITS ^ 0xffff)) {
  504.         printf("\nUsage:  expandwi attrib [filespec [filespec] ...]\n");
  505.         printf("        where attrib is file attribute byte in hex.\n");
  506.         return (255);
  507.     }
  508.  
  509.     printf("\nFile names requested with attribute byte of 0x%X\n", attrib);
  510.  
  511.     printf("\nexpandwild() input strings (count = %d)\n", argc - 2);
  512.     for (i = 2; i < argc; i++)
  513.         printf("  %s\n", argv[i]);
  514.  
  515.     rc = expandwild(&newargc, &newargv, -1, &argv[2], attrib);
  516.  
  517.     printf("\nexpandwild() return code = %d (%s)\n", rc, rmsg[rc]);
  518.  
  519.     if (rc == 0) {
  520.         printf("\nexpandwild() expanded output strings (count = %d)\n",
  521.           newargc);
  522.         for (i = 0; i < newargc; i++)
  523.             printf("  %s\n", newargv[i]);
  524.     }
  525.  
  526.     return (rc);
  527.  
  528. }   /* main() */
  529.  
  530.  
  531. /*  Convert ASCII string of hex digits to int.  Return 0xffff if invalid digits
  532.     or overflow detected; warning: also returned for ASCII string "FFFF".  */
  533.  
  534. #include <ctype.h>
  535.  
  536. unsigned int xtoi(char x[])     /* x is input ASCII hex string, can be null */
  537. {
  538.     unsigned int xw;            /* work area for current hex digit */
  539.     unsigned int ix = 0;        /* return value accumulator */
  540.  
  541.     for (; *x != '\0'; ++x) {
  542.         if (!isascii(xw = *x))
  543.             return (0xffff);    /* invalid digit */
  544.         xw = toupper(xw);
  545.         if (xw >= '0' && xw <= '9')
  546.             xw -= '0';
  547.         else if (xw >= 'A' && xw <= 'F')
  548.             xw -= 'A' - 0xA;
  549.         else
  550.             return (0xffff);    /* invalid digit */
  551.         if (ix < 0x1000) {      /* overflow? */
  552.             ix <<= 4;           /* make room for current digit */
  553.             ix |= xw;           /* add current digit */
  554.         }
  555.         else
  556.             return (0xffff);    /* overflow */
  557.     }
  558.  
  559.     return (ix);
  560.  
  561. }   /* xtoi() */
  562.  
  563. #endif  /* #if defined(MAIN) */
  564.  
  565. /*---------------------------------------------------------------------------*/
  566.